{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Mutual Information Minimization Demo\n",
    "\n",
    "In this notebook, we provide a demo for how to use estimators in `mi_estimators.py` to minimize mutual information with sample pairs under multivariate Gaussian setups."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "from mi_estimators import *"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "First, we define a Gaussian sampler to generate Gaussian samples which are differentiable to the covariance coefficients. More specifically, if $\\left[\\begin{array}{c} x \\\\ y \\end{array}\\right] \\sim \\mathcal{N}\\left(\\left[\\begin{array}{c} 0\\\\0\\end{array}\\right], \\left[\\begin{array}{cc} 1 &\\rho \\\\ \\rho & 1\\end{array} \\right] \\right) $, we can parameterize the covariance matrix by $\\left[\\begin{array}{cc} 1 &\\rho \\\\ \\rho & 1\\end{array} \\right] = {SS}^T$ with $S =\\left[\\begin{array}{cc} \\cos \\theta &\\sin \\theta \\\\ -\\sin \\theta & \\cos \\theta \\end{array} \\right]$. Then $\\left[\\begin{array}{c} x \\\\ y \\end{array}\\right] = Sz$ with $z$ as a standard Gaussian random vector. We aim to optimize parameter $\\theta$ to minimize the mutual information between $x$ and $y$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "class GaussianSampler(nn.Module):\n",
    "    def __init__(self, dim, para_list = None):\n",
    "        super(GaussianSampler, self).__init__()\n",
    "        self.dim = dim\n",
    "        if para_list is None:\n",
    "            para_list = [0.55] * dim\n",
    "        self.p_theta_ = torch.nn.Parameter(torch.tensor(para_list, requires_grad = True))\n",
    "        \n",
    "    def get_trans_mat(self):\n",
    "        p_theta = self.p_theta_.cuda().unsqueeze(-1)\n",
    "        #p_theta = torch.softmax(p_theta, dim = 0)\n",
    "\n",
    "        trans_row1 = torch.cat((torch.sin(p_theta),torch.cos(p_theta)), dim=-1).unsqueeze(-1)\n",
    "        trans_row2 = torch.cat((torch.cos(p_theta),torch.sin(p_theta)), dim=-1).unsqueeze(-1)  #[dim, 2,1]\n",
    "        return torch.cat((trans_row1, trans_row2), dim=-1)  #[dim,2,2]\n",
    "\n",
    "    def gen_samples(self, num_sample, cuda = True):\n",
    "        noise= torch.randn(self.dim,num_sample,2).cuda()\n",
    "        trans_mat = self.get_trans_mat()\n",
    "        samples = torch.bmm(noise, trans_mat).transpose(0,1) #[dim, nsample, 2]\n",
    "        if not cuda:\n",
    "            samples = samples.cpu().detach().numpy()\n",
    "        return samples[:,:,0], samples[:,:,1] \n",
    "\n",
    "    def get_covariance(self):\n",
    "        p_theta = self.p_theta_.cuda()\n",
    "        return (2.*torch.sin(p_theta)*torch.cos(p_theta))\n",
    "\n",
    "    def get_MI(self):\n",
    "        rho = self.get_covariance()\n",
    "        return -1./2.*torch.log(1-rho**2).sum().item()\n",
    "        #return -self.dim /2.*torch.log(1-rho**2 / 2).sum().item()\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "lr = 1e-4\n",
    "batch_size = 100\n",
    "num_iter = 5000\n",
    "sample_dim = 2\n",
    "hidden_size = 5\n",
    "estimator_name = \"CLUB\" "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can plot the sample pairs of variable $x$ and $y$, which has a high linear correlation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "sampler = GaussianSampler(sample_dim).cuda()\n",
    "#print(\"The corvariance of Gaussian is {}\".format(sampler.get_covariance().cpu().detach().numpy()))\n",
    "x_sample, y_sample = sampler.gen_samples(1000, cuda = False)\n",
    "plt.scatter(x_sample, y_sample)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Then we optimize parameter $\\theta$ to minimize the mutual information with only samples from the Gaussian distribution."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "step 0, true MI value 1.5803104639053345\n",
      "step 100, true MI value 1.5547454357147217\n",
      "step 200, true MI value 1.4817274808883667\n",
      "step 300, true MI value 1.3839462995529175\n",
      "step 400, true MI value 1.2832202911376953\n",
      "step 500, true MI value 1.1905152797698975\n",
      "step 600, true MI value 1.1002705097198486\n",
      "step 700, true MI value 1.0157833099365234\n",
      "step 800, true MI value 0.9356847405433655\n",
      "step 900, true MI value 0.8612485527992249\n",
      "step 1000, true MI value 0.7927320003509521\n",
      "step 1100, true MI value 0.7293397188186646\n",
      "step 1200, true MI value 0.6697946786880493\n",
      "step 1300, true MI value 0.6151266098022461\n",
      "step 1400, true MI value 0.5645853281021118\n",
      "step 1500, true MI value 0.5182494521141052\n",
      "step 1600, true MI value 0.4745531678199768\n",
      "step 1700, true MI value 0.4329792261123657\n",
      "step 1800, true MI value 0.3949650526046753\n",
      "step 1900, true MI value 0.3580608367919922\n",
      "step 2000, true MI value 0.3230716288089752\n",
      "step 2100, true MI value 0.29075807332992554\n",
      "step 2200, true MI value 0.26167789101600647\n",
      "step 2300, true MI value 0.2344626784324646\n",
      "step 2400, true MI value 0.20971505343914032\n",
      "step 2500, true MI value 0.18751351535320282\n",
      "step 2600, true MI value 0.16782349348068237\n",
      "step 2700, true MI value 0.15008166432380676\n",
      "step 2800, true MI value 0.1341300755739212\n",
      "step 2900, true MI value 0.11967259645462036\n",
      "step 3000, true MI value 0.10675829648971558\n",
      "step 3100, true MI value 0.09495552629232407\n",
      "step 3200, true MI value 0.084212526679039\n",
      "step 3300, true MI value 0.07457525283098221\n",
      "step 3400, true MI value 0.06576594710350037\n",
      "step 3500, true MI value 0.05779126286506653\n",
      "step 3600, true MI value 0.05062354728579521\n",
      "step 3700, true MI value 0.044180355966091156\n",
      "step 3800, true MI value 0.03822943568229675\n",
      "step 3900, true MI value 0.032884467393159866\n",
      "step 4000, true MI value 0.028074178844690323\n",
      "step 4100, true MI value 0.023795776069164276\n",
      "step 4200, true MI value 0.020110558718442917\n",
      "step 4300, true MI value 0.01680823229253292\n",
      "step 4400, true MI value 0.013881937600672245\n",
      "step 4500, true MI value 0.011373257264494896\n",
      "step 4600, true MI value 0.009163863956928253\n",
      "step 4700, true MI value 0.007274009753018618\n",
      "step 4800, true MI value 0.005683435592800379\n",
      "step 4900, true MI value 0.004356834106147289\n"
     ]
    }
   ],
   "source": [
    "mi_estimator = eval(estimator_name)(sample_dim, sample_dim, hidden_size).cuda()\n",
    "\n",
    "sampler_optimizer = torch.optim.Adam(sampler.parameters(), lr = lr)\n",
    "mi_optimizer = torch.optim.Adam(mi_estimator.parameters(), lr = lr)\n",
    "\n",
    "mi_true_values = []\n",
    "mi_est_values = []\n",
    "min_mi = 100.\n",
    "\n",
    "for i in range(num_iter):\n",
    "    sampler.train()\n",
    "    mi_estimator.eval()\n",
    "    x_samples, y_samples = sampler.gen_samples(batch_size)\n",
    "    sampler_loss = mi_estimator(x_samples, y_samples)\n",
    "    sampler_optimizer.zero_grad()\n",
    "    sampler_loss.backward() # retain_graph=True)\n",
    "    sampler_optimizer.step()\n",
    "\n",
    "    for j in range(5):\n",
    "        mi_estimator.train()\n",
    "        x_samples, y_samples = sampler.gen_samples(batch_size)\n",
    "        mi_loss = mi_estimator.learning_loss(x_samples, y_samples)\n",
    "        mi_optimizer.zero_grad()\n",
    "        mi_loss.backward()\n",
    "        mi_optimizer.step()\n",
    "\n",
    "    mi_true_values.append(sampler.get_MI())\n",
    "    mi_est_values.append(mi_estimator(x_samples, y_samples))\n",
    "    if i % 100 ==0:\n",
    "        print(\"step {}, true MI value {}\".format(i, sampler.get_MI()))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can plot the true MI values and the estimated MI values in each batch. The true MI value continuously decreases during the training. The estimated MI value first increases then decreases. The beginning increasing of estimated MI is because the estimator has not learned well from the samples. Then the decreasing process is the result of minimizing MI as learning loss."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.plot(np.arange(len(mi_est_values)), mi_est_values, label=estimator_name + \" est\")\n",
    "plt.plot(np.arange(len(mi_true_values)), mi_true_values, label=\"True MI value\")\n",
    "plt.legend()\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can plot samples of the optimized Gaussian sampler again, where the linear correlation between $x$ and $y$ has disappeared."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "x_sample, y_sample = sampler.gen_samples(1000, cuda=False)\n",
    "plt.scatter(x_sample, y_sample)\n",
    "plt.show()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
